home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / HAPN.C < prev    next >
Text File  |  1993-08-09  |  12KB  |  509 lines

  1. /*  Driver for HAPN-1 8273 card on PC
  2.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  3.  *  Modified Rx interrupt routine to prevent lockup
  4.  *  John Tanner VK2ZXQ 6th Feb 1988
  5.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  6.  */
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #include "global.h"
  10. #include "config.h"
  11. #ifdef HAPN
  12. #ifdef    ANSIPROTO
  13. #include <stdarg.h>
  14. #endif
  15. #include "timer.h"
  16. #include "mbuf.h"
  17. #include "iface.h"
  18. #include "pktdrvr.h"
  19. #include "netuser.h"
  20. #include "hapn.h"
  21. #include "ax25.h"
  22. #include "trace.h"
  23. #include "pc.h"
  24. #include "proc.h"
  25.  
  26. static void cmd_8273 __ARGS((int16 base,int cmd,int np,...));
  27. static int hapn_init __ARGS((struct hapn *hp));
  28. static int hapn_raw __ARGS((struct iface *iface,struct mbuf *bp));
  29. static int hapn_stop __ARGS((struct iface *iface,int temp));
  30. static int hcdchk __ARGS((int16 base));
  31. static void hrxint __ARGS((struct hapn *hp));
  32. static void hrxgo __ARGS((struct hapn *hp));
  33. static void htxint __ARGS((void *p));
  34.  
  35. static struct hapn Hapn[NHAPN];
  36. static INTERRUPT (*H_handle[])() = { ha0vec };
  37. static int16 Nhapn;
  38.  
  39. /*  send command to the 8273
  40.  *  "base" = base port of 8273
  41.  *  "cmd"  = command byte
  42.  *  "np"   = number of parameter bytes
  43.  *  "p1"   = first parameter (parameters are int)
  44.  */
  45. #ifdef    ANSIPROTO
  46. static void
  47. cmd_8273(int16 base, int cmd, int np, ...)
  48. {
  49.     int p;
  50.     va_list ap;
  51.  
  52.     while(inportb(base+STA) & CBSY)
  53.         ;
  54.     outportb(base+HCMD, cmd);
  55.  
  56.     va_start(ap,np);
  57.     while(np--){
  58.         while(inportb(base+STA) & CPBF)
  59.             ;
  60.         p = va_arg(ap,int);
  61.         outportb(base+PAR, p);
  62.     }
  63.     va_end(ap);
  64. }
  65. #else
  66. /*VARARGS3*/
  67. static void
  68. cmd_8273(base, cmd, np, p1)
  69. int16 base;
  70. int cmd, np, p1;
  71. {
  72.     int *p;
  73.  
  74.     while(inportb(base+STA) & CBSY)
  75.         ;
  76.     outportb(base+HCMD, cmd);
  77.     p = &p1;
  78.     while(np--){
  79.         while(inportb(base+STA) & CPBF)
  80.             ;
  81.         outportb(base+PAR, *p++);
  82.     }
  83. }
  84. #endif
  85. /*  Start receiver of 8273 */
  86. static void
  87. hrxgo(hp)
  88. struct hapn *hp;
  89. {
  90.     cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  91. }
  92.  
  93. /*  Interrupt service function.  Entered with hapn index
  94.  *  The "flag" variable is used in this routine to indicate a
  95.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  96.  *  the 8273 is reset.
  97.  */
  98. void
  99. haint(dev)
  100. int dev;
  101. {
  102.     struct hapn *hp = &Hapn[dev];
  103.     int16 base = hp->base;
  104.     char flag = 0;
  105.  
  106.     /*  Check for TX interrupt  */
  107.     if(inportb(base+STA) & TXINT){
  108.         flag = 1;    /* Valid interrupt, set flag */
  109.         htxint(hp);
  110.     }
  111.     /*  Check for RX interrupt  */
  112.     if(inportb(base+STA) & RXINT){
  113.         flag = 1;    /* Valid interrupt, set flag */
  114.         hrxint(hp);
  115.     }
  116.     /* Check for unknown interrupt  */
  117.     if(!flag){
  118.         hp->badint++;    /* Increment error counter */
  119.         hapn_init(hp);    /* Reinitialise the 8273 */
  120.     }
  121. }
  122. /*  RX interrupt service
  123.  *  if status Register bit "RXIRA" is set, interrupt is final,
  124.  *  otherwise, interrupt is data request
  125.  */
  126. static void
  127. hrxint(hp)
  128. struct hapn *hp;
  129. {
  130.     struct mbuf *bp;
  131.     unsigned char results[10];
  132.     struct phdr *phdr;
  133.  
  134.     int16 base = hp->base;
  135.     hp->rxints++;
  136.  
  137.     if(inportb(base+STA) & RXIRA){
  138.         /* RX result interrupt
  139.          * If the result is a good frame 3 bytes need to be read
  140.          * If an error has occurred only one byte need to be read
  141.          */
  142.  
  143.         /* Read first result byte and test for good data */
  144.         if((results[0]=(inportb(base + RXI))) == 0xe0){
  145.             /* Good result; read two more result bytes */
  146.             while((inportb(base + STA) & RXIRA) == 0)
  147.                 ;
  148.             /* Read second result byte */
  149.             results[1] = inportb(base + RXI);
  150.             /* Wait for third result byte  */
  151.             while((inportb(base + STA) & RXIRA) == 0)
  152.                 ;  
  153.             results[2] = inportb(base + RXI);/* Read it */
  154.  
  155.             /* Since this frame is ok put it on the queue */
  156.             bp = alloc_mbuf(sizeof(struct phdr));
  157.             bp->cnt = sizeof(struct phdr);
  158.             phdr = (struct phdr *)bp->data;
  159.             phdr->iface = hp->iface;
  160.             phdr->type = CL_AX25;
  161.             bp->next = hp->rcvbuf;
  162.             hp->rcvbuf = NULLBUF;
  163.             enqueue(&Hopper, bp);
  164.             hp->rframes++;
  165.         } else {
  166.             /* Error termination
  167.              * Parse RIC and act accordingly
  168.              * Only one result byte returned on error
  169.              */
  170.             switch(results[0]){
  171.             case CRCERR:
  172.                 hp->crcerr++;
  173.                 break;
  174.             case ABORT_DET:
  175.                 hp->aborts++;
  176.                 break;
  177.             case DMA_OVRN:
  178.                 hp->dmaorun++;
  179.                 break;
  180.             case MEM_OVFL:
  181.                 hp->toobig++;
  182.                 break;
  183.             case CD_LOSS:
  184.                 hp->cdloss++;
  185.                 hapn_init(hp);    /* 8273 reset on cd error */
  186.                 break;
  187.             case RX_ORUN:
  188.                 hp->rxorun++;
  189.                 break;
  190.             }
  191.             /* Throw rx buffer contents away to start over */
  192.             hp->rcp = hp->rcvbuf->data;
  193.             hp->rcvbuf->cnt = 0;
  194.         }
  195.         /* Restart the receiver */
  196.         cmd_8273(base,RX_DISABLE,0);
  197.         hrxgo(hp);
  198.     } else {
  199.         /* RX data interrupt; allocate new rx buffer if none present */
  200.         if((bp = hp->rcvbuf) == NULLBUF){
  201.             if((bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz)) == NULLBUF) {
  202.                 /* No memory available */
  203.                 hp->nomem++;
  204.                 cmd_8273(base, RX_DISABLE, 0);
  205.                 hrxgo(hp);
  206.                 return;
  207.             }
  208.             /* Init buffer pointer */
  209.             hp->rcp = hp->rcvbuf->data;
  210.         }
  211.         /*  Barf if rx data is more than buffer can hold (should never
  212.          *  happen since 8273 is also counting bytes).
  213.          */
  214.         if(bp->cnt++ >= hp->bufsiz){
  215.             hp->toobig++;
  216.             cmd_8273(base, RX_DISABLE, 0);
  217.             hrxgo(hp);
  218.             free_p(bp);
  219.             hp->rcvbuf = NULLBUF;
  220.             return;
  221.         }
  222.         /* Store the received byte */
  223.         *hp->rcp++ = inportb(base+RXD);
  224.     }
  225. }
  226.  
  227. /*  test for busy channel (CD active)
  228.  *  returns TRUE if channel busy
  229.  */
  230. static int
  231. hcdchk(base)
  232. int16 base;
  233. {
  234.     DISABLE();
  235.  
  236.     cmd_8273(base, READ_A, 0);
  237.     while(!(inportb(base+STA) & CRBF))
  238.         ;
  239.  
  240.     RESTORE();
  241.     return((inportb(base+RES) & CD) != 0);
  242. }
  243.  
  244. /*  TX interrupt service
  245.  *  if status Register bit "TXIRA" is set, interrupt is final,
  246.  *  otherwise, interrupt is data request
  247.  */
  248. static void
  249. htxint(p)
  250. void *p;
  251. {
  252.     struct hapn *hp = (struct hapn *)p;
  253.     int16 len, base = hp->base;
  254.     int c = 0;
  255.     hp->txints++;
  256.  
  257.     DISABLE();
  258.  
  259.     if(inportb(base+STA) & TXIRA){        /* TX result interupt */
  260.         hp->tstate = IDLE;
  261.         free_p(hp->sndbuf);
  262.         hp->sndbuf = NULLBUF;
  263.  
  264.         /*  Read result  */
  265.         while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  266.             ;
  267.         c = inportb(base+TXI);
  268.  
  269.         /*  Test for tx abort  */
  270.         switch(c & 0x1f){
  271.         case DMA_URUN:
  272.             hp->t_urun++;
  273.             break;
  274.         case CTS_LOSS:
  275.             hp->ctsloss++;
  276.             break;
  277.         case ABORT_CMPLT:
  278.             hp->taborts++;
  279.             break;
  280.         }
  281.     }
  282.     switch(hp->tstate){
  283.     case IDLE:    /*  See if a buffer is ready to be sent  */
  284.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  285.             break;
  286.  
  287.     case DEFER:    /*  Busy-channel check  */
  288.         if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  289.             if(hcdchk(base)){
  290.                 hp->tstate = DEFER;
  291.                 start_timer(&hp->defer);
  292.                 break;
  293.             }
  294.         }
  295.         /*  Start transmitter  */
  296.         stop_timer(&hp->defer);
  297.         len = len_p(hp->sndbuf);
  298.         cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  299.         hp->tstate = ACTIVE;
  300.         hp->tframes++;
  301.         break;
  302.     case ACTIVE:    /*  Get next byte to send  */
  303.         if((c = PULLCHAR(&hp->sndbuf)) == -1){
  304.             cmd_8273(base, ABORT_TXF, 0);
  305.             hp->tstate = IDLE;
  306.         } else
  307.             outportb(base+TXD, c);
  308.         break;
  309.     }
  310.     RESTORE();
  311. }
  312.  
  313. /*  Attach a HAPN adaptor to the system
  314.  *  argv[0]:  hardware type, must be "hapn"
  315.  *  argv[1]:  I/O address, e.g. "0x310"
  316.  *  argv[2]:  vector, e.g. "2"
  317.  *  argv[3]:  mode, must be "ax25"
  318.  *  argv[4]:  interface name, e.g. "ha0"
  319.  *  argv[5]:  rx packet buffer size in bytes
  320.  *  argv[6]:  maximum transmission unit in bytes
  321.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  322.  *   notused:
  323.  *  argv[8]: IP address, optional (defaults to Ip_addr)
  324.  */
  325. int
  326. hapn_attach(argc, argv,p)
  327. int argc;
  328. char *argv[];
  329. void *p;
  330. {
  331.     struct iface *if_h;
  332.     struct hapn *hp;
  333.     int dev, i, i_state;
  334.  
  335.  
  336.     static struct {
  337.         char *str;
  338.         char type;
  339.     } ch_access [] = { "csma", 0, "full", 1 };
  340.  
  341.     if(*Mycall == '\0'){
  342.         tputs(Nomycall);
  343.         return -1;
  344.     }
  345.     if(stricmp(argv[3],"AX25") != 0) {
  346.         tputs("Mode must be AX25\n");
  347.         return -1;
  348.     }
  349.     if(if_lookup(argv[4]) != NULLIF){
  350.         tprintf(Ifexist,argv[4]);
  351.         return -1;
  352.     }
  353.     if(Nhapn >= NHAPN){
  354.         tprintf("Max %d HAPN adaptors\n",NHAPN);
  355.         return -1;
  356.     }
  357.     /*  Create new interface structure  */
  358.     if_h = mxallocw(sizeof(struct iface));
  359.  
  360.     /*  Set interface address  */
  361.     if_h->addr = Ip_addr;
  362.  
  363.     dev = Nhapn++;
  364.     hp = &Hapn[dev];
  365.  
  366.     /*  Initialize hardware constants */
  367.     hp->base = htoi(argv[1]);
  368.     hp->vec = htoi(argv[2]);
  369.  
  370.     /*  Save original interrupt vector  */
  371.     hp->oldvec = getirq(Hapn[dev].vec);
  372.  
  373.     /*  Set new interrupt vector  */
  374.     setirq(hp->vec, H_handle[dev]);
  375.  
  376.     /* Continue filling interface structure */
  377.     if_h->name = strxdup(argv[4]);
  378.     if_h->type = CL_AX25;
  379.     if_h->mtu = atoi(argv[6]);
  380.     if_h->dev = dev;
  381.     if_h->stop = hapn_stop;
  382.     if_h->output = ax_output;
  383.     if_h->raw = hapn_raw;
  384.     hp->iface = if_h;
  385.  
  386.     if_h->send = ax_send;
  387.     if_h->hwaddr = strxdup(Mycall);
  388.  
  389.     /* Link the interface into the interface list  */
  390.     if_h->next = Ifaces;
  391.     if_h->niface = Niface++;
  392.     Ifaces = if_h;
  393.  
  394.     /*  Fill the local data structure  */
  395.     hp->bufsiz = atoi(argv[5]);
  396.     for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  397.         if(!strcmp(argv[7], ch_access[i].str))
  398.             hp->mode = ch_access[i].type;
  399.  
  400.     /*  Initialize the hardware  */
  401.     DISABLE();
  402.     hapn_init(hp);
  403.  
  404.     /* Initialize the defer timer */
  405.     set_timer(&hp->defer,1*MSPTICK);
  406.     hp->defer.func = htxint;
  407.     hp->defer.arg = hp;
  408.  
  409.     /*  Enable the interrupt  */
  410.     maskon(hp->vec);
  411.  
  412.     RESTORE();
  413.     return 0;
  414. }
  415.  
  416. /*  initialize the HAPN adaptor */
  417. static int
  418. hapn_init(hp)
  419. struct hapn *hp;
  420. {
  421.     int16 base = hp->base;
  422.  
  423.     DISABLE();
  424.     /*  Reset the 8273 */
  425.     outportb(base+RST, 1);
  426.     outportb(base+RST, 0);
  427.     inportb(base+TXI);        /* Clear any old IR contents */
  428.     inportb(base+RXI);
  429.  
  430.     /*  Select the operating modes  */
  431.     cmd_8273(base, SET_XFER, 1, 1);
  432.     cmd_8273(base, SET_MODE, 1, HDLC | EARLY | PREFRM | FLG_STM);
  433.     cmd_8273(base, SET_SERIAL, 1, NRZI);
  434.     cmd_8273(base, SET_B, 1, IRQ_ENB | RTS);
  435.     cmd_8273(base, RST_B, 1, 0xff ^ RTS);
  436.     hrxgo(hp);
  437.     RESTORE();
  438.     return 0;
  439. }
  440.  
  441. /*  shut down the HAPN adaptor */
  442. static int
  443. hapn_stop(iface,temp)
  444. struct iface *iface;
  445. int temp;
  446. {
  447.  
  448.     int dev = iface->dev;
  449.     struct hapn *hp = &Hapn[dev];
  450.     int16 base = hp->base;
  451.  
  452.     /*  Mask off interrupt input  */
  453.     maskoff(hp->vec);
  454.  
  455.     /*  Restore original interrupt vector  */
  456.     setirq(hp->vec,hp->oldvec);
  457.  
  458.     /*  Reset the 8273  */
  459.     outportb(base+RST, 1);
  460.     outportb(base+RST, 0);
  461.     return 0;
  462. }
  463.  
  464. /* Display adaptor statistics */
  465. int
  466. dohapnstat(argc,argv,p)
  467. int argc;
  468. char *argv[];
  469. void *p;
  470. {
  471.     struct hapn *hp;
  472.     int i;
  473.  
  474.     if(Nhapn == 0){
  475.         tputs("No HAPN adaptor attached\n");
  476.         return 1;
  477.     }
  478.     for(i = 0; i < Nhapn; i++){
  479.         hp = &Hapn[i];
  480.         tprintf("HAPN %d:   rxints: %ld   txints: %ld   badint: %-5d\n", i,
  481.          hp->rxints,hp->txints,hp->badint);
  482.         tprintf(" receive  - frames:  %-5d  crcerrs: %-5d  aborts: %-5d  dmaorun: %-5d\n",
  483.          hp->rframes,hp->crcerr, hp->aborts, hp->dmaorun);
  484.         tprintf("          - toobig:  %-5d  dcdloss: %-5d  rxorun: %-5d\n",
  485.          hp->toobig,hp->cdloss,hp->rxorun);
  486.         if(tprintf(" transmit - frames:  %-5d  aborts : %-5d  uruns : %-5d  ctsloss: %-5d\n",
  487.          hp->tframes,hp->taborts, hp->t_urun, hp->ctsloss) == EOF)
  488.             break;
  489.     }
  490.     return 0;
  491. }
  492.  
  493. /* Send raw packet on HAPN interface */
  494. static int
  495. hapn_raw(iface,bp)
  496. struct iface *iface;
  497. struct mbuf *bp;
  498. {
  499.     struct hapn *hp = &Hapn[iface->dev];
  500.  
  501.     enqueue(&hp->sndq, bp);
  502.  
  503.     /*  See if anything being transmitted  */
  504.     if(hp->tstate == IDLE)
  505.         htxint(hp);
  506.     return 0;
  507. }
  508.  
  509. #endif /* HAPN */